#include "RPTree.h"
#include "RPLeaf.h"
#include "RPWrapper.h"

#include <iostream>
#include <fstream>

using namespace CVGreyc::NDArray;

/* Wrapper for RPTree */

extern "C"
{
	void* RPTree_new( double *data, unsigned int rows,
			  unsigned int columns, unsigned int min_size,
			  unsigned int maxdepth, double c,
			  unsigned int *leavesContent)
	{
		void* ret = NULL;
		list< list<unsigned int> > leavesContentCpp;
		CArray<double> data_(data,rows,columns);
		RPTreeParam param(data_, min_size, maxdepth, c );
		ret = new RPTree( param, leavesContentCpp );

		if( leavesContent )
		{
			unsigned int cnt = 0;
			for( list< list<unsigned int> >::iterator i = leavesContentCpp.begin() ; i !=leavesContentCpp.end() ; i++ )
			{
				for( list<unsigned int>::iterator j = i->begin() ; j != i->end() ; j++ )
				{
					leavesContent[*j] = cnt;
				}
				cnt++;
			}
		}

		return ret;
	}

	void* RPTree_load( const char *file )
	{
		return (void*) RPTree::load( *(new ifstream(file)) );
	}

	void RPTree_save( void *rptree, const char* file )
	{
		((RPTree*) rptree)->save( *(new ofstream(file)) );
	}

	void RPTree_print( void *rptree )
	{
		((RPTree*) rptree)->save( cout );
	}

	void RPTree_delete( void* rptree )
	{
		delete (RPTree*) rptree;
	}

	unsigned int RPTree_use( void *rptree, double *data )
	{
		return ((RPTree*) rptree)->use( data );
	}

	void RPTree_multi_use( void *rptree, double *data, unsigned int rows, unsigned int *result )
	{
		const CVGreyc::NDArray::CArray<double> ndArray( data, rows, ((RPTree*) rptree)->get_dim() );
		((RPTree*) rptree)->use(ndArray,result);
	}

	void RPTree_get_v( void *rptree, double *v )
	{
		RPTree& tree = *(RPTree*)rptree;
		for (size_t i = 0; i<tree.get_dim(); i++) v[i] = tree.get_v()[i];
	}

	void   *RPTree_get_left( void *rptree )
	{
		return (void*) &((RPTree*) rptree)->get_left();
	}

	void   *RPTree_get_right( void *rptree )
	{
		return (void*) &((RPTree*) rptree)->get_right();
	}

	int    RPTree_get_usedRule( void *rptree )
	{
		return ((RPTree*) rptree)->get_usedRule();
	}

	double RPTree_get_threshold( void *rptree )
	{
		return ((RPTree*) rptree)->get_threshold();
	}

	double RPTree_get_mean( void *rptree )
	{
		return ((RPTree*) rptree)->get_mean();
	}

	unsigned int RPTree_get_dim( void *rptree )
	{
		return ((RPTree*) rptree)->get_dim();
	}

	unsigned int RPTree_get_depth( void *rptree )
	{
		return ((RPTree*) rptree)->get_depth();
	}

	void *RPTree_get_leaf_by_id( void *rptree, unsigned int id )
	{
		return (void*) (((RPTree*) rptree)->get_leaf_by_id(id));
	}
	
	bool RPTree_isLeaf(void* rptree){
		return static_cast<RPTree*>(rptree)->get_usedRule()==-1;
	}

	/* Wrapper for RPLeaf */


	void *RPLeaf_new( unsigned int depth, unsigned int id )
	{
		return (void*) new RPLeaf( depth, id );
	}

	unsigned int RPLeaf_use( void *rpleaf, double *data )
	{
		return ((RPLeaf*) rpleaf)->use( data );
	}

	void RPLeaf_delete( void *rpleaf )
	{
		delete (RPLeaf*) rpleaf;
	}

	unsigned int RPLeaf_get_id( void *rpleaf )
	{
		return ((RPLeaf*) rpleaf)->get_id();
	}

	unsigned int RPLeaf_get_depth( void *rpleaf )
	{
		return ((RPTree*) rpleaf)->get_depth();
	}

} // extern "C"
